home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 40
/
Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso
/
Aminet
/
util
/
sys
/
NewSearch.lha
/
NewSearch
/
source
/
Search.c
< prev
Wrap
C/C++ Source or Header
|
2000-10-21
|
14KB
|
556 lines
/*
File: Search.c
Author: Neil Cafferkey
Placed in the public domain by Neil Cafferkey.
*/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/locale.h>
#include <exec/memory.h>
#include <dos/dos.h>
typedef ULONG UPINT;
#define DOS_VERSION 37
#define LOCALE_VERSION 38
#define PATH_BUF_SIZE 512
#define SPACES_SIZE 160+1
#define MARGIN 3
#define INDENT 5
#define DIR_MARGIN 2
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct LocaleBase *LocaleBase;
enum
{
ARG_FROM,
ARG_SEARCH,
ARG_ALL,
ARG_NONUM,
ARG_QUIET,
ARG_QUICK,
ARG_FILE,
ARG_PATTERN,
ARG_COUNT
};
VOID PrintFullName(TEXT *buffer,UWORD cut_off,struct AnchorPath *anchor);
UWORD GetDirName(struct AnchorPath *anchor,TEXT *buffer);
BOOL FindString(struct AnchorPath *anchor,UPINT *args,TEXT *pattern,
struct Locale *locale,UBYTE *pi);
BOOL MatchStringNoCase(TEXT *string,TEXT *text,TEXT *text_end,UBYTE *pi,
struct Locale *locale);
ULONG strlen(STRPTR s);
extern const TEXT template[];
extern const TEXT dos_name[];
extern const TEXT locale_name[];
extern const TEXT control_codes[];
extern const TEXT line_show[];
extern const TEXT wild_card[];
extern const TEXT new_line[];
extern const TEXT abandon_msg[];
ULONG Search(VOID)
{
UPINT *args;
struct RDArgs *read_args;
struct DosLibrary *dos_base;
struct LocaleBase *locale_base;
struct AnchorPath *anchor;
LONG error,return_code=RETURN_WARN;
TEXT *text,*spaces,*pattern=NULL,*path_buffer,*user_pattern=NULL,*p,ch,
**from;
BOOL found,success=TRUE,new_dir,print_names;
UWORD indent=0,pat_buf_length,cut_off,pat_length;
UBYTE k,q;
struct Locale *locale;
/* Open libraries */
SysBase=*((APTR *)sizeof(APTR));
dos_base=(struct DosLibrary *)OpenLibrary(dos_name,DOS_VERSION);
if(!dos_base)
return RETURN_FAIL;
DOSBase=dos_base;
locale_base=(struct LocaleBase *)OpenLibrary(locale_name,LOCALE_VERSION);
/* Allocate buffers */
spaces=AllocMem(SPACES_SIZE,MEMF_CLEAR);
anchor=AllocMem(sizeof(struct AnchorPath),MEMF_CLEAR);
args=AllocMem(ARG_COUNT*sizeof(APTR),MEMF_CLEAR);
path_buffer=AllocMem(PATH_BUF_SIZE,MEMF_ANY);
if(args&&anchor&&locale_base&&spaces&&path_buffer)
{
LocaleBase=locale_base;
locale=OpenLocale(NULL);
for(text=spaces+SPACES_SIZE-1;text>spaces;*(--text)=' ');
/* Parse arguments */
read_args=ReadArgs(template,args,NULL);
if(locale&&read_args)
{
/* Prepare the pattern to be matched */
pat_length=strlen((TEXT *)args[ARG_SEARCH]);
pat_buf_length=pat_length*2+3;
user_pattern=AllocMem(pat_length+5,MEMF_CLEAR);
pattern=AllocMem(pat_buf_length,MEMF_ANY);
if(user_pattern&&pattern)
{
if(args[ARG_PATTERN]||args[ARG_FILE])
{
if(args[ARG_FILE])
text=user_pattern;
else
{
text=user_pattern+2;
CopyMem(wild_card,user_pattern,2);
CopyMem(wild_card,text+pat_length,2);
}
CopyMem((TEXT *)args[ARG_SEARCH],text,pat_length);
if(ParsePatternNoCase(user_pattern,pattern,pat_buf_length)<0)
success=FALSE;
}
else
{
/* Copy the search string and convert it to uppercase */
text=pattern;
for(p=(TEXT *)args[ARG_SEARCH];(ch=*p)!='\0';p++)
*(text++)=ConvToUpper(locale,ch);
*text='\0';
/* Construct prefix table for Knuth-Morris-Pratt algorithm */
*user_pattern=0;
k=0;
for(q=1;q<pat_length;q++)
{
while(k&&(pattern[k]!=pattern[q]))
k=user_pattern[k-1];
if(pattern[k]==pattern[q])
k++;
user_pattern[q]=k;
}
}
}
else
success=FALSE;
/* Get the next starting point */
for(from=*(((TEXT ***)args)+ARG_FROM);*from&&success;from++)
{
/* Initialise file search */
anchor->ap_BreakBits=SIGBREAKF_CTRL_C;
anchor->ap_FoundBreak=0;
anchor->ap_Flags=0;
error=MatchFirst(*from,anchor);
/* Work out if more than one file is being searched */
print_names=(*(*(((TEXT ***)args)+ARG_FROM)+1))
||(anchor->ap_Flags&APF_ITSWILD);
/* Enter sub-dir if the pattern was an explicitly named dir */
if(!(anchor->ap_Flags&APF_ITSWILD)
&&(anchor->ap_Info.fib_DirEntryType>0))
anchor->ap_Flags|=APF_DODIR;
/* Set flag to get name of starting directory */
new_dir=TRUE;
/* Traverse the directory */
while(!error&&success)
{
found=FALSE;
if(anchor->ap_Info.fib_DirEntryType>0)
{
/* Enter sub-dir if the ALL switch was supplied and we're
not on the way out of it */
if(!(anchor->ap_Flags&APF_DIDDIR))
{
if(!(args[ARG_FILE]||args[ARG_QUIET]||args[ARG_QUICK]))
{
WriteChars(spaces,MARGIN+INDENT*indent+DIR_MARGIN);
text=(TEXT *)&(anchor->ap_Info.fib_FileName);
VPrintf("%s (dir)\n",&text);
}
if(args[ARG_ALL]||(anchor->ap_Flags&APF_DODIR))
{
anchor->ap_Flags|=APF_DODIR;
indent++;
print_names=TRUE;
}
}
else
{
indent--;
}
new_dir=TRUE;
anchor->ap_Flags&=~APF_DIDDIR;
}
else
{
/* Deal with a file */
if(anchor->ap_Flags&APF_DirChanged)
new_dir=TRUE;
if(new_dir)
{
if(!(cut_off=GetDirName(anchor,path_buffer)))
success=FALSE;
new_dir=FALSE;
}
if(args[ARG_FILE])
{
found=MatchPatternNoCase(pattern,
(TEXT *)&(anchor->ap_Info.fib_FileName));
}
else
{
if(args[ARG_QUICK])
{
PrintFullName(path_buffer,cut_off,anchor);
WriteChars(control_codes,3);
}
else if(!args[ARG_QUIET]&&print_names)
{
WriteChars(spaces,MARGIN+INDENT*indent);
text=(TEXT *)&(anchor->ap_Info.fib_FileName);
VPrintf("%s..\n",&text);
}
found=FindString(anchor,args,pattern,locale,
user_pattern);
}
if(found)
{
if(args[ARG_FILE]||args[ARG_QUIET]&&!args[ARG_QUICK])
{
PrintFullName(path_buffer,cut_off,anchor);
PutStr(new_line);
}
return_code=RETURN_OK;
}
}
error=MatchNext(anchor);
if(error&&(error!=ERROR_NO_MORE_ENTRIES))
{
success=FALSE;
SetIoErr(error);
}
}
}
/* Clear line for next shell prompt */
if(args[ARG_QUICK]&&!args[ARG_FILE])
WriteChars(control_codes,2);
MatchEnd(anchor);
if(success)
SetIoErr(0);
}
FreeArgs(read_args);
CloseLocale(locale);
}
else
{
SetIoErr(ERROR_NO_FREE_STORE);
}
/* Free memory */
if(args)
FreeMem(args,ARG_COUNT*sizeof(APTR));
if(anchor)
FreeMem(anchor,sizeof(struct AnchorPath));
if(spaces)
FreeMem(spaces,SPACES_SIZE);
if(path_buffer)
FreeMem(path_buffer,PATH_BUF_SIZE);
if(user_pattern)
FreeMem(user_pattern,pat_length+5);
if(pattern)
FreeMem(pattern,pat_buf_length);
/* Close libraries and exit */
if(locale_base)
CloseLibrary((struct Library *)LocaleBase);
CloseLibrary((struct Library *)DOSBase);
/* Check and reset signals */
if(SetSignal(0,-1)&SIGBREAKF_CTRL_C)
SetIoErr(ERROR_BREAK);
/* Exit */
if(error=IoErr())
{
PrintFault(error,NULL);
return RETURN_FAIL;
}
return return_code;
}
VOID PrintFullName(TEXT *buffer,UWORD cut_off,struct AnchorPath *anchor)
{
buffer[cut_off]='\0';
if(AddPart(buffer,(TEXT *)&(anchor->ap_Info.fib_FileName),PATH_BUF_SIZE))
{
PutStr(buffer);
}
return;
}
UWORD GetDirName(struct AnchorPath *anchor,TEXT *buffer)
{
if(NameFromLock(anchor->ap_Current->an_Lock,buffer,
PATH_BUF_SIZE))
return strlen(buffer);
return 0;
}
BOOL FindString(struct AnchorPath *anchor,UPINT *args,TEXT *pattern,
struct Locale *locale,UBYTE *pi)
{
BOOL found=FALSE,end_early=FALSE,line_matches,at_end;
BPTR old_lock,file;
TEXT *p,*q,*r,*line,*buffer=NULL,ch;
UPINT max_line_length=0,line_length,offset=0,file_size,buf_size,
line_start=0,line_count=1;
ULONG sigs;
LONG read_length=1;
/* Move into the file's directory */
old_lock=CurrentDir(anchor->ap_Current->an_Lock);
/* Open the file for reading */
if(file=Open((TEXT *)&(anchor->ap_Info.fib_FileName),MODE_OLDFILE))
{
/* Get a buffer for the file */
file_size=anchor->ap_Info.fib_Size;
buf_size=file_size+1;
while(!buffer&&buf_size)
{
if(!(buffer=AllocMem(buf_size,MEMF_ANY)))
buf_size>>=1;
}
/* Check size of buffer */
if((buf_size<=file_size)&&buffer)
{
/* Get length of longest line */
while(read_length>0)
{
read_length=Read(file,buffer,buf_size-1);
q=buffer+read_length;
if(!read_length)
q++;
for(p=buffer;p<q;p++)
if((*p=='\n')||!read_length)
{
line_length=offset+(p-buffer)-line_start;
if(line_length>max_line_length)
max_line_length=line_length;
line_start=offset+(p-buffer)+1;
}
offset+=read_length;
}
/* Ensure buffer is big enough for longest line */
if(buf_size<=max_line_length)
{
buf_size=max_line_length+1;
buffer=AllocMem(buf_size,MEMF_ANY);
}
}
/* Test every line against the pattern */
if(buffer&&pattern)
{
read_length=Seek(file,0,OFFSET_BEGINNING)+1;
while(((read_length=Read(file,buffer,buf_size-1))>0)&&!end_early)
{
q=buffer+read_length;
at_end=Seek(file,0,OFFSET_CURRENT)==file_size;
if(at_end)
*(q++)='\0';
line=buffer;
for(p=buffer;(p<q)&&!end_early;p++)
{
ch=*p;
if((ch=='\n')||(ch=='\0'))
{
*p='\0';
if(args[ARG_PATTERN])
line_matches=MatchPatternNoCase(pattern,line);
else
line_matches=
MatchStringNoCase(pattern,line,p,pi,locale);
if(line_matches)
{
if(!found&&args[ARG_QUICK])
PutStr(new_line);
found=TRUE;
if(args[ARG_QUIET])
{
end_early=TRUE;
}
else
{
if(!args[ARG_NONUM])
VPrintf("%6lu ",&line_count);
/* Replace invisible characters with dots */
for(r=line;r<p;r++)
if(!IsPrint(locale,*r))
*r='.';
VPrintf("%s\n",&line);
}
}
line=p+1;
if(ch=='\n')
line_count++;
sigs=SetSignal(0,SIGBREAKF_CTRL_D);
if(sigs&(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D))
{
end_early=TRUE;
if(sigs&SIGBREAKF_CTRL_D)
{
PutStr(abandon_msg);
}
}
}
}
/* Start reading again at start of most recent line */
if(!at_end)
Seek(file,line-q,OFFSET_CURRENT);
}
}
if(buffer)
FreeMem(buffer,buf_size);
Close(file);
}
CurrentDir(old_lock);
return found;
}
const TEXT template[]=
"FROM/M,SEARCH/A,ALL/S,NONUM/S,QUIET/S,QUICK/S,FILE/S,PATTERN/S";
const TEXT version_string[]="$VER: Search 41.2 (14.10.2000)";
const TEXT dos_name[]=DOSNAME;
const TEXT locale_name[]="locale.library";
const TEXT control_codes[]={0x9b,'K',13};
const TEXT wild_card[]={'#','?'};
const TEXT new_line[]="\n";
const TEXT abandon_msg[]="** File abandoned\n";
BOOL MatchStringNoCase(TEXT *string,TEXT *text,TEXT *text_end,UBYTE *pi,
struct Locale *locale)
{
TEXT *s,ch;
s=string;
while(text<text_end)
{
ch=ConvToUpper(locale,*(text++));
while((s!=string)&&(*s!=ch))
s=string+pi[s-string-1];
if(ch==*s)
s++;
if(!*s)
return TRUE;
}
return FALSE;
}
ULONG strlen(STRPTR s)
{
STRPTR p;
p=s;
for(p=s;*p!='\0';p++);
return p-s;
}